<?php

namespace app\common\model\merchant;

use app\common\model\BaseModel;
use think\Exception;
use think\facade\Db;

/**
 * 待发放红包记录表
 */
class PendingRedPacketModel extends BaseModel
{
    protected $name = 'pending_red_packet';

    // 成功状态
    public const STATUS_SUCCESS = 1;
    // 失败状态
    public const STATUS_FAIL = 2;
    // 增加金额
    public const OP_ADD = '+';
    // 减少金额
    public const OP_SUB = '-';

    // 设置字段信息
    protected $schema = [
        'id' => 'int',        //
        'mer_id' => 'string',        // 商户码
        'type' => 'int',        // 1 虚码 2实码
        'used_log_id' => 'int',        // 关联记录id
        'salesman_id' => 'int',        // 导购ID
        'red_packet' => 'float',        // 红包金额
        'status' => 'int',        // 状态 0:待发放,   1:已发送 2: 发放失败,
        'op_user' => 'int',        // 操作人
        'create_at' => 'datetime',        // 创建时间
        'pay_time' => 'datetime',        // 支付时间
        'fail_reason' => 'string',        // 失败原因
        'order_no' => 'string',        // 订单号
        'update_at' => 'datetime',        // 更新时间
        'out_pay_order' => 'string',        // 外部支付单号
    ];

    /**
     *  红包记录
     * @param $mer_id |商户
     * @param $type |1 虚码 2实码
     * @param $used_log_id |关联记录id
     * @param $salesman_id |导购ID
     * @param $red_packet |红包金额
     * @param string $op_user |操作人
     * @param int $status |状态 0:待发放, 1:已发送 2: 发放失败
     * @param int $fail_reason |失败原因
     */
    public function add($mer_id, $type, $used_log_id, $salesman_id, $red_packet, $op_user = '', $status = 0, $fail_reason = '')
    {
        $order_no = make_unique_no(substr($mer_id, -6));
        $this->db()->insert([
            'mer_id' => $mer_id,
            'order_no' => $order_no,
            'type' => $type,
            'used_log_id' => $used_log_id,
            'salesman_id' => $salesman_id,
            'red_packet' => $red_packet,
            'op_user' => $op_user,
            'status' => $status,
            'fail_reason' => $fail_reason,
        ]);

    }

    /**
     * 获取待处理的记录
     * @param int $limit
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getPendingRecord(int $limit = 500): array
    {
        $result = $this->db()->where('status', 0)->limit($limit)
            ->order('id asc')
            ->field('id,mer_id,order_no,used_log_id,red_packet,salesman_id')
            ->select();
        if (!empty($result)) {
            $result = $this->getValidRecord($result);

        }


        return $result;
    }


    /**
     * 获取有效待发记录
     * @param array $record
     * @return void
     * @throws \think\db\exception\DbException
     */
    protected function getValidRecord(array &$record): array
    {
        $mer_ids = array_keys(array_flip(array_column($record, 'mer_id')));
        $salesman_ids = array_keys(array_flip(array_column($record, 'salesman_id')));
        $salesman_list = $this->db('shop_salesman')->removeOption()
            ->whereIn('mer_id', $mer_ids)
            ->whereIn('id', $salesman_ids)
            ->where('status', 1)
            ->column('name,open_id', 'id');
        $vp_title = $this->db('virtual_used_log')
            ->where('id','in',array_column($record,'used_log_id'))->column('vp_title','id');
        $result = [];
        foreach ($record as $row) {
            // 判断导购是否存在
            if (!isset($salesman_list[$row['salesman_id']])) {
                $this->updatePendingRecord($row['id'], $row['used_log_id'], self::STATUS_FAIL, '导购不存在或已停用');
                continue;
            }
            // 导购
            if (empty($salesman_list[$row['salesman_id']]['name']) || empty($salesman_list[$row['salesman_id']]['open_id'])) {
                $this->updatePendingRecord($row['id'], $row['used_log_id'], self::STATUS_FAIL, '导购姓名或微信未绑定');
                continue;
            }
            if (!isset($vp_title[$row['used_log_id']])){
                $this->updatePendingRecord($row['id'], $row['used_log_id'], self::STATUS_FAIL, '活动未找到');
                continue;
            }
            $row['name'] = $salesman_list[$row['salesman_id']]['name'];
            $row['open_id'] = $salesman_list[$row['salesman_id']]['open_id'];
            $row['vp_title'] = $vp_title[$row['used_log_id']];

            $result[] = $row;
        }
        return $result;
    }

    /**
     * 获取商户记录
     * @param array $mer_ids
     * @return array
     */
    public function getMerchantBalance(array $mer_ids): array
    {
        return $this->db('merchant_stock')->removeOption()
            ->whereIn('mer_id', $mer_ids)
            ->column('balance', 'mer_id');
    }

    /**
     * 更新商户余额
     * @param string $mer_id 商户编号
     * @param float $money 红包金额
     * @param string $op 操作
     * @param float $reMoney 操作后金额
     * @return bool
     */
    public function updateMerchantBalance(string $mer_id, float $money, string $op, &$reMoney): bool
    {
        try {
            $map['mer_id'] = $mer_id;
            $result = $this->db('merchant_stock')->removeOption()
                ->where($map)->update(['balance' => Db::raw('balance' . $op . $money)]);
            if ($result === 0) {
                return false;
            }
            if ($op === self::OP_SUB) {
                $reMoney = $this->db('merchant_stock')->where($map)->value('balance');
            } else {
                $reMoney = 0;
            }
            return true;
        } catch (Exception $e) {
            return false;
        }
    }

    /**
     * 更新发放记录
     * @param int $id 记录ID
     * @param int $status 状态
     * @param string $fail 失败原因
     * @param string $out_pay_order 支付单号
     * @return void
     * @throws \think\db\exception\DbException
     */
    public function updatePendingRecord(int $id, int $log_id, int $status, string $fail = '', string $out_pay_order = ''): void
    {
        $now = date('Y-m-d H:i:s');
        $updateData = [
            'status' => $status,
            'fail_reason' => $fail,
            'out_pay_order' => $out_pay_order,
            'update_at' => $now,
        ];
        if ($status === 1) {
            $updateData['pay_time'] = $now;
        }
        // 更新状态
        $this->db()->where('id', $id)->update($updateData);


        $updateLogData = [
            'status' => $status === self::STATUS_SUCCESS ? 8 : 3,
            'update_at' => $now,
            'fail_reason' => $fail
        ];
        //  更新日志
        $this->db('virtual_used_log')->where('id', $log_id)->update($updateLogData);

    }

    /**
     * 插入商户的余额变动记录
     * @param string $mer_id
     * @param $chang_money
     * @param $money
     * @param string $order_no
     * @param string $reason
     * @return int|string
     */
    public function insertMoneyLog(string $mer_id, $chang_money, $money, string $order_no, string $reason = '扫码红包')
    {
        return $this->db('merchant_money_log')->insert([
            'mer_id' => $mer_id,
            'type' => 2,
            'money' => $chang_money,  //变动金额
            're_money' => $money,  //变动后金额
            'memo' => '扫码红包',
            'pay_order' => $order_no,
            'op_user' => 0,
            'create_at' => date('Y-m-d H:i:s'),
            'reason' => $reason,
        ]);
    }

    /**
     * 根据ID 获取 支付的结果
     * @param string $merid 商户号
     * @param array $ids 日志ID
     * @return array
     */
    public function getPayStatusForIds(string $merid, array $ids): array
    {
        return $this->db()->where('mer_id', $merid)->whereIn('used_log_id', $ids)
            ->column('status as pay_status,pay_time,update_at as pay_update_at,fail_reason as pay_fail_reason', 'used_log_id');
    }

    /**
     * 支付红包记录
     * @param string $merId 商户ID
     * @param array $ids 要支付的ID
     * @return integer
     * @throws \think\db\exception\DbException
     */
    public function payRedPacket(string $merId, array $ids)
    {

        $this->db('virtual_used_log')->where('mer_id', $merId)->whereIn('id', $ids)
            ->where('status', 3)
            ->update(['status' => 1, 'fail_reason' => '', 'update_at' => date('Y-m-d H:i:s')]);

        return $this->db()->where('mer_id', $merId)->whereIn('used_log_id', $ids)
            ->where('status', 2)
            ->update(['status' => 0, 'fail_reason' => '', 'update_at' => date('Y-m-d H:i:s')]);

    }
}
